package com.dagger.utils;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


/**
 * httpclient调用的简单封装
 * 基于java11
 * @author 海
 *
 */
public class HttpRequestUtils {
	private int connectTimeout=30*1000;//连接超时时间，毫秒
	private int requestTimeout=30*1000;//请求超时时间，毫秒
	private HttpClient httpClient=null;
	
	/**
	 * 
	 * @param connectTimeout 连接超时时间，毫秒
	 * @param requestTimeout 请求超时时间，毫秒
	 */
	public HttpRequestUtils(int connectTimeout,int requestTimeout){
		this.connectTimeout = connectTimeout;
		this.requestTimeout = requestTimeout;
		init();
	}
		
	public HttpRequestUtils(){
		init();
	}	
	
	private void init(){
		SSLParameters sslParams = new SSLParameters();	
		sslParams.setEndpointIdentificationAlgorithm("");
		
		TrustManager[] trustAllCertificates = new TrustManager[] { new X509TrustManager() {
			@Override
			public X509Certificate[] getAcceptedIssuers() {
				return null; // Not relevant.
			}
			@Override
			public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
				// TODO Auto-generated method stub
			}
			@Override
			public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
				// TODO Auto-generated method stub
			}
		} };
		
		System.setProperty("jdk.internal.httpclient.disableHostnameVerification","true");//取消主机名验证
		
		SSLContext ssl;
		try {
			ssl = SSLContext.getInstance("SSL");
			ssl.init(null, trustAllCertificates, new SecureRandom());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
				
		//忽略ssl证书		
		this.httpClient = HttpClient.newBuilder()
				.sslContext(ssl)
				.sslParameters(sslParams)
				.connectTimeout(Duration.ofMillis(connectTimeout))
				.build();
	}
	
	/**
	 * 通过HttpGet请求服务方法
	 * @param serviceUrl 请求地址
	 * @return
	 */
	public String doHttpGet(String serviceUrl) {
		return doHttpGet(serviceUrl,null);
	}
	public String doHttpGet(String serviceUrl,Map<String,Object> paramMap) {
		
		serviceUrl = formatUrl(serviceUrl);
		
		String params = this.getGetParams(paramMap);
		
		if(params!=null && params.length()>0){
			serviceUrl =serviceUrl+"?"+params;
			System.out.println("Get request from:"+serviceUrl);
		}
		HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(serviceUrl))
				.timeout(Duration.ofMillis(requestTimeout))
				.GET().build();
		return this.doHttp(httpRequest);
	}
	
	public String formatUrl(String serviceUrl){
		if(serviceUrl==null || serviceUrl.trim().length()==0){
			throw new RuntimeException("ServiceUrl can not be null!");			
		}
		serviceUrl=serviceUrl.trim();
		if(serviceUrl.endsWith("/"))
			serviceUrl=serviceUrl.substring(0,serviceUrl.length()-1);
		
		return serviceUrl;
	}
	
	/**
	 *  get方法的参数处理
	 *  
	 * @param paramMap
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	private String getGetParams(Map<String,Object> paramMap){		
		if(paramMap==null || paramMap.isEmpty())
			return null;
		
		StringBuffer params=new StringBuffer();  	
		Set<String> keySet = paramMap.keySet();
		Object value;
		for(String key:keySet){
			value = paramMap.get(key);
			if(value instanceof String) {
				try {
					value = URLEncoder.encode((String)value, "UTF-8");
				} catch (UnsupportedEncodingException e) {
					throw new RuntimeException(e);
				}			
			}
			params.append("&").append(key).append("=").append(value);
			
		}
    	return params.toString().substring(1);
	}
	
	/**
	 * 通过HttpPost请求
	 * @param serviceUrl
	 * @param paramMap 键值对参数
	 * @return
	 */
	public String doHttpPostParams(String serviceUrl,Map<String,Object> paramMap){	
		
		serviceUrl = formatUrl(serviceUrl);
		String paramString = paramMap.keySet().stream()
				.map(key -> String.format("%s=%s", key,URLEncoder.encode(paramMap.get(key).toString(), StandardCharsets.UTF_8)))
				.collect(Collectors.joining("&"));
		
		HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(serviceUrl))
				.timeout(Duration.ofMillis(requestTimeout))
				.setHeader("Content-Type", "application/x-www-form-urlencoded")
				.POST(BodyPublishers.ofString(paramString)).build();
		
    	return this.doHttp(httpRequest);		    	
	}
	
	
	
	
	/**
	 * 删除请求
	 * @param serviceUrl
	 * @return
	 */
	public String doHttpDelete(String serviceUrl){	
		
		serviceUrl = formatUrl(serviceUrl);
		
		HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(serviceUrl))
				.timeout(Duration.ofMillis(requestTimeout))
				.DELETE().build();
		
    	return this.doHttp(httpRequest);		    	
	}

	/**
	 * put json请求
	 * @param serviceUrl
	 * @param json JSON格式字符串
	 * @return
	 */
	public String doHttpPutJson(String serviceUrl,String json){	
		
		serviceUrl = formatUrl(serviceUrl);
		
		HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(serviceUrl))
				.timeout(Duration.ofMillis(requestTimeout))
				.setHeader("Content-Type", "application/json")
				.PUT(BodyPublishers.ofString(json)).build();
		
    	return this.doHttp(httpRequest);
	}
	
//	public String doHttpPostFile(String serviceUrl,Map<String,Object> paramMap){	
		
		//无法用原生的java11来实现，需要引入
	//可使用org.apache.httpcomponents(httpclient及httpmime)的MultipartEntityBuilder构建multipartEntity，最后通过HttpRequest.BodyPublishers.ofInputStream来传递内容
    	
//	}
	
	
	/**
	 * post json请求
	 * @param serviceUrl
	 * @param json JSON格式字符串
	 * @return
	 */
	public String doHttpPostJson(String serviceUrl,String json){	
		
		serviceUrl = formatUrl(serviceUrl);
		HttpRequest httpRequest = HttpRequest.newBuilder(URI.create(serviceUrl))
				.timeout(Duration.ofMillis(requestTimeout))
				.setHeader("Content-Type", "application/json")
				.POST(BodyPublishers.ofString(json)).build();
		
    	return this.doHttp(httpRequest);		    	
	}
	
	private String doHttp(HttpRequest httpRequest) {
		try {
			HttpResponse<String> httpResponse = httpClient.send(httpRequest, BodyHandlers.ofString());
		    if(httpResponse.statusCode() == 200 || httpResponse.statusCode() == 201){
		    	return 	httpResponse.body();
		    }else{
		    	String errorMsg = "";
		    	try{
		    		errorMsg = httpResponse.body();
		    	}catch(Exception e){}
		    	throw new RuntimeException("Service request faild["+httpResponse.statusCode()+"]:"+errorMsg);	
		    }
		    
		} catch (Exception e) {			
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

}
